package com.kantboot.system.user.service.impl;

import com.kantboot.api.varcode.domain.dto.ApiVarCodeDTO;
import com.kantboot.api.varcode.service.IApiVarCodeService;
import com.kantboot.functional.common.service.ICommonKantbootRsaService;
import com.kantboot.system.user.dao.repository.entity.SysUserThirdPartyRepository;
import com.kantboot.system.user.dao.repository.vo.SysUserVOOfSelfRepository;
import com.kantboot.system.user.domain.entity.SysUserThirdParty;
import com.kantboot.system.user.domain.vo.SysUserOfSelfVO;
import com.kantboot.system.user.exception.SystemUserException;
import com.kantboot.system.user.service.ISysTokenService;
import com.kantboot.system.user.service.ISysUserBindService;
import com.kantboot.system.user.service.IUserSelfService;
import com.kantboot.util.common.exception.BaseException;
import com.kantboot.util.common.http.HttpRequestHeaderUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class SysUserBindServiceImpl implements ISysUserBindService
{

    @Resource
    private IUserSelfService userSelfService;

    @Resource
    private IApiVarCodeService apiVarCodeService;

    @Resource
    private SysUserVOOfSelfRepository repository;

    @Resource
    private SysUserThirdPartyRepository userThirdPartyRepository;

    @Resource
    private ISysTokenService tokenService;

    @Resource
    private HttpRequestHeaderUtil httpRequestHeaderUtil;

    @Resource
    private ICommonKantbootRsaService kantbootRsaService;




    /**
     * 临时用户根据手机号码+验证码绑定
     * @param phone 手机号码
     * @param varCode 验证码
     * @return 登录VO
     */
    @Override
    public SysUserOfSelfVO bindWithPhoneAndVarCodeAtTemporary(String phone, String varCode) {
        // 如果没有绑定

        // 验证码DTO
        ApiVarCodeDTO dto = new ApiVarCodeDTO();
        dto.setTo(phone);
        dto.setTypeCode("sms");
        dto.setSceneCode("bindAtTemporary");
        dto.setValue(varCode);
        // 验证验证码是否正确
        if(!apiVarCodeService.check(dto)){
            // 验证码错误，抛出异常，提示前端验证码错误
            throw SystemUserException.VAR_CODE_ERROR;
        }

        // 再次确认是否已经绑定过了
        Long selfId = userSelfService.getSelfId();
        SysUserOfSelfVO self = repository.findById(selfId).orElseThrow(() -> BaseException.of("notLogin", "未登录"));
        if(self.getPhone()!=null){
            // 如果已经绑定过了，抛出异常，提示前端不可重复绑定
            throw BaseException.of("alreadyBind", "不可重复绑定");
        }

        // 检查手机号码是否已经被绑定
        SysUserOfSelfVO byPhone = repository.findByPhone(phone);
        if(byPhone!=null){
            // 判断用户邮箱是否为空
            if(self.getEmail()!=null&&byPhone.getEmail()==null){
                byPhone.setEmail(self.getEmail());
            }
            // 如果检查的用户的邮箱不为空，且不等于当前用户的邮箱，抛出异常，提示前端手机号码已被绑定
            if(byPhone.getEmail()!=null&&!byPhone.getEmail().equals(self.getEmail())){
                throw BaseException.of("phoneConflict", "手机号码已被绑定");
            }

            // 将第三方账号绑定到已有账号
            List<SysUserThirdParty> fromThird = userThirdPartyRepository.findByUserId(self.getId());
            List<SysUserThirdParty> toThird = userThirdPartyRepository.findByUserId(byPhone.getId());
            // 检查是否有双方都有的第三方用户
            for (SysUserThirdParty from : fromThird) {
                for (SysUserThirdParty to : toThird) {
                    if(from.getThirdPartyCode().equals(to.getThirdPartyCode())&&from.getKey().equals(to.getKey())){
                        throw BaseException.of("thirdPartyConflict", "有重复绑定的第三方");
                    }
                }
            }
            for (SysUserThirdParty sysUserThirdParty : fromThird) {
                sysUserThirdParty.setUserId(byPhone.getId());
            }
            userThirdPartyRepository.saveAll(fromThird);
            tokenService.updateUserIdByToken(httpRequestHeaderUtil.getToken(), byPhone.getId());
            byPhone.setIsTemporary(false);
            byPhone = repository.save(byPhone);
            // 删除临时用户
            repository.deleteById(self.getId());
            return byPhone;
        }

        // 如果没绑定过手机号，就绑定
        self.setPhone(phone);
        self.setIsTemporary(false);
        repository.save(self);
        return self;
    }

    /**
     * 临时用户根据邮箱+验证码绑定
     * @param email 邮箱
     * @param varCode 验证码
     * @return 登录VO
     */
    @Override
    public SysUserOfSelfVO bindWithEmailAndVarCodeAtTemporary(String email, String varCode) {

        // 验证码DTO
        ApiVarCodeDTO dto = new ApiVarCodeDTO();
        dto.setTo(email);
        dto.setTypeCode("email");
        dto.setSceneCode("bindAtTemporary");
        dto.setValue(varCode);
        // 验证验证码是否正确
        if(!apiVarCodeService.check(dto)){
            // 验证码错误，抛出异常，提示前端验证码错误
            throw SystemUserException.VAR_CODE_ERROR;
        }
        // 再次确认是否已经绑定过了
        Long selfId = userSelfService.getSelfId();
        SysUserOfSelfVO self = repository.findById(selfId).orElseThrow(() -> BaseException.of("notLogin", "未登录"));
        if(self.getEmail()!=null){
            // 如果已经绑定过了，抛出异常，提示前端不可重复绑定
            throw BaseException.of("alreadyBind", "不可重复绑定");
        }

        // 检查邮箱是否已经被绑定
        SysUserOfSelfVO byEmail = repository.findByEmail(email);
        if(byEmail!=null) {
            // 判断用户手机号码是否为空
            if (self.getPhone() != null && byEmail.getPhone() == null) {
                byEmail.setPhone(self.getPhone());
            }
            // 如果检查的用户的手机号码不为空，且不等于当前用户的手机号码，抛出异常，提示前端邮箱已被绑定
            if (byEmail.getPhone() != null && !byEmail.getPhone().equals(self.getPhone())) {
                throw BaseException.of("emailConflict", "邮箱已被绑定");
            }

            // 将第三方账号绑定到已有账号
            List<SysUserThirdParty> fromThird = userThirdPartyRepository.findByUserId(self.getId());
            List<SysUserThirdParty> toThird = userThirdPartyRepository.findByUserId(byEmail.getId());
            // 检查是否有双方都有的第三方用户
            for (SysUserThirdParty from : fromThird) {
                for (SysUserThirdParty to : toThird) {
                    if (from.getThirdPartyCode().equals(to.getThirdPartyCode()) && from.getKey().equals(to.getKey())) {
                        throw BaseException.of("thirdPartyConflict", "有重复绑定的第三方");
                    }
                }
            }
            for (SysUserThirdParty sysUserThirdParty : fromThird) {
                sysUserThirdParty.setUserId(byEmail.getId());
            }
            userThirdPartyRepository.saveAll(fromThird);
            tokenService.updateUserIdByToken(httpRequestHeaderUtil.getToken(), byEmail.getId());
            byEmail.setIsTemporary(false);
            byEmail = repository.save(byEmail);
            // 删除临时用户
            repository.deleteById(self.getId());
            return byEmail;
        }

        // 如果没绑定过邮箱，就绑定
        self.setEmail(email);
        self.setIsTemporary(false);
        repository.save(self);
        return self;
    }

    /**
     * 临时用户根据手机号码+验证码绑定（安全）
     * @param phone 手机号码
     * @param varCode 验证码
     * @return 登录VO
     */
    @Override
    public SysUserOfSelfVO bindWithPhoneAndVarCodeAtTemporaryWithSecurity(String phone, String varCode) {
        String phoneDecrypted = kantbootRsaService.decryptAndDelete(phone);
        String varCodeDecrypted = kantbootRsaService.decryptAndDelete(varCode);
        return bindWithPhoneAndVarCodeAtTemporary(phoneDecrypted,varCodeDecrypted);
    }

    /**
     * 临时用户根据邮箱+验证码绑定（安全）
     * @param email 邮箱
     * @param varCode 验证码
     * @return 登录VO
     */
    @Override
    public SysUserOfSelfVO bindWithEmailAndVarCodeAtTemporaryWithSecurity(String email, String varCode) {
        String emailDecrypted = kantbootRsaService.decryptAndDelete(email);
        String varCodeDecrypted = kantbootRsaService.decryptAndDelete(varCode);
        return bindWithEmailAndVarCodeAtTemporary(emailDecrypted,varCodeDecrypted);
    }

    @Override
    public SysUserOfSelfVO skipTemporaryBind() {
        Long selfId = userSelfService.getSelfId();
        SysUserOfSelfVO self = repository.findById(selfId).orElseThrow(() -> BaseException.of("notLogin", "未登录"));
        self.setIsTemporary(false);
        return repository.save(self);
    }
}
